#include "vector.hh"

template <unsigned int U, typename T>
Vector<U, T>::Vector ()
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] = 0;
}

template <unsigned int U, typename T>
Vector<U, T>::Vector (T val1, T val2)
{
  assert (U >= 2);

  vect_[0] = val1;
  vect_[1] = val2;

  for (unsigned int i = 2; i < U; ++i)
    vect_[i] = 0;
}

template <unsigned int U, typename T>
Vector<U, T>::Vector (T val1, T val2, T val3)
{
  assert (U >= 3);

  vect_[0] = val1;
  vect_[1] = val2;
  vect_[2] = val3;

  for (unsigned int i = 3; i < U; ++i)
    vect_[i] = 0;
}

template <unsigned int U, typename T>
Vector<U, T>::Vector (T val1, T val2, T val3, T val4)
{
  assert (U >= 4);

  vect_[0] = val1;
  vect_[1] = val2;
  vect_[2] = val3;
  vect_[3] = val4;

  for (unsigned int i = 4; i < U; ++i)
    vect_[i] = 0;
}

template <unsigned int U, typename T>
Vector<U, T>::Vector (const Vector<U, T>& point1, const Vector<U, T>& point2)
{
  for (unsigned i = 0; i < U; ++i)
    vect_[i] = point2 (i) - point1 (i);
}

template <unsigned int U, typename T>
Vector<U, T>::Vector (Vector<U, T>& vect)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] = vect (i);
}

template <unsigned int U, typename T>
Vector<U, T>::Vector (const Vector<U, T>& vect)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] = vect (i);
}

template <unsigned int U, typename T>
void
Vector<U, T>::operator() (unsigned int pos, T val)
{
  assert (pos < U);

  vect_[pos] = val;
}

template <unsigned int U, typename T>
void
Vector<U, T>::operator() (Vector<U, T>& vect)
{
  for (unsigned i = 0; i < U; ++i)
    vect_[i] = vect (i);
}

template <unsigned int U, typename T>
void
Vector<U, T>::val_set (T v1, T v2)
{
  assert (U >= 2);

  vect_[0] = v1;
  vect_[1] = v2;
}

template <unsigned int U, typename T>
void
Vector<U, T>::val_set (T v1, T v2, T v3)
{
  assert (U >= 3);

  vect_[0] = v1;
  vect_[1] = v2;
  vect_[2] = v3;
}

template <unsigned int U, typename T>
void
Vector<U, T>::val_set (T v1, T v2, T v3, T v4)
{
  assert (U >= 4);

  vect_[0] = v1;
  vect_[1] = v2;
  vect_[2] = v3;
  vect_[3] = v4;
}

template <unsigned int U, typename T>
T
Vector<U, T>::operator() (unsigned int pos) const
{
  assert (pos < U);

  return vect_[pos];
}

template <unsigned int U, typename T>
Vector<U, T>&
Vector<U, T>::operator= (const Vector<U, T>& vect)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] = vect (i);

  return *this;
}

template <unsigned int U, typename T>
Vector<U, T>&
Vector<U, T>::operator+= (const Vector<U, T>& vect)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] += vect (i);

  return *this;
}

template <unsigned int U, typename T>
Vector<U, T>&
Vector<U, T>::operator-= (const Vector<U, T>& vect)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] -= vect (i);

  return *this;
}

template <unsigned int U, typename T>
Vector<U, T>&
Vector<U, T>::operator+= (const T& f)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] += f;

  return *this;
}

template <unsigned int U, typename T>
Vector<U, T>&
Vector<U, T>::operator-= (const T& f)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] -= f;

  return *this;
}

template <unsigned int U, typename T>
Vector<U, T>&
Vector<U, T>::operator*= (const T& f)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] *= f;

  return *this;
}

template <unsigned int U, typename T>
Vector<U, T>&
Vector<U, T>::operator/= (const T& f)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] /= f;

  return *this;
}

template <unsigned int U, typename T>
Vector<U, T>&
Vector<U, T>::operator%= (const int& f)
{
  for (unsigned int i = 0; i < U; ++i)
    vect_[i] = ((int) vect_[i]) % f;

  return *this;
}

//******************************

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::operator+ (const Vector<U, T>& vect) const
{
  Vector<U, T> res;

  for (unsigned int i = 0; i < U; ++i)
    res (i, vect_[i] + vect (i));

  return res;
}

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::operator- (const Vector<U, T>& vect)
{
  Vector<U, T> res;

  for (unsigned int i = 0; i < U; ++i)
    res (i, vect_[i] - vect (i));

  return res;
}

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::operator+ (const T& f)
{
  Vector<U, T> res;

  for (unsigned int i = 0; i < U; ++i)
    res (i, vect_[i] + f);

  return res;
}

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::operator- (const T& f)
{
  Vector<U, T> res;

  for (unsigned int i = 0; i < U; ++i)
    res (i, vect_[i] - f);

  return res;
}

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::operator* (const T& f)
{
  Vector<U, T> res;

  for (unsigned int i = 0; i < U; ++i)
    res (i, vect_[i] * f);

  return res;
}

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::operator/ (const T& f)
{
  Vector<U, T> res;

  for (unsigned int i = 0; i < U; ++i)
    res (i, vect_[i] / f);

  return res;
}

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::operator% (const int& f)
{
  Vector<U, T> res;

  for (unsigned int i = 0; i < U; ++i)
    res (i, ((int) vect_[i]) % f);

  return res;
}

template <unsigned int U, typename T>
bool
Vector<U, T>::operator== (Vector<U, T>& vect)
{
  for (unsigned int i = 0; i < U; ++i)
    if (vect_[i] != vect (i))
      return false;

  return true;
}

template <unsigned int U, typename T>
bool
Vector<U, T>::operator== (const Vector<U, T>& vect)
{
  for (unsigned int i = 0; i < U; ++i)
    if (vect_[i] != vect (i))
      return false;

  return true;
}

template <unsigned int U, typename T>
bool
Vector<U, T>::operator!= (Vector<U, T>& vect) const
{
  for (unsigned int i = 0; i < U; ++i)
    if (vect_[i] != vect (i))
      return true;

  return false;
}

template <unsigned int U, typename T>
bool
Vector<U, T>::operator!= (const Vector<U, T>& vect) const
{
  for (unsigned int i = 0; i < U; ++i)
    if (vect_[i] != vect (i))
      return true;

  return false;
}

template <unsigned int U, typename T>
float
Vector<U, T>::scalar (Vector<U, T>& vect)
{
  float res = 0;

  for (unsigned int i = 0; i < U; ++i)
    res += vect_[i] * vect (i);

  return res;
}

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::vectorial (Vector<U, T>& vect)
{
  Vector<U, T> res;

  assert (U == 3);

  res (0, vect_[1] * vect (2) - vect_[2] * vect (1));
  res (1, vect (0) * vect_[2] - vect (2) * vect_[0]);
  res (2, vect_[0] * vect (1) - vect_[1] * vect (0));

  return res;
}

template <unsigned U, typename T>
Vector<U, T>
Vector<U, T>::vectorial (const Vector<U, T>& p1, const Vector<U, T>& p2, const Vector<U, T>& p3)
{
  Vector<U, T> res;

  assert (U == 3);

  float v1x = p2 (0) - p1 (0);
  float v1y = p2 (1) - p1 (1);
  float v1z = p2 (2) - p1 (2);

  float v2x = p3 (0) - p1 (0);
  float v2y = p3 (1) - p1 (1);
  float v2z = p3 (2) - p1 (2);

  res (0, v1y * v2z - v1z * v2y);
  res (1, v1z * v2x - v1x * v2z);
  res (2, v1x * v2y - v1y * v2x);

  return res;
}

template <unsigned int U, typename T>
float
Vector<U, T>::get_norme () const
{
  float res = 0;

  for (unsigned int i = 0; i < U; ++i)
    res += vect_[i] * vect_[i];

  return sqrt(res);
}

template <unsigned int U, typename T>
T
Vector<U, T>::operator& (const T& f)
{
  T res = vect_[0];
  T tmp = f;

  for (unsigned int i = 1; i < U; ++i)
    {
      res += vect_[i] * tmp;
      tmp *= tmp;
    }

  return res;
}

template <unsigned int U, typename T>
Vector<U, T>
Vector<U, T>::zero ()
{
  Vector<U, T> res;

  return res;
}

template <unsigned int U, typename T>
void
Vector<U, T>::print () const
{
  std::cout << "X: " << vect_[0] << " "
	    << "Y: " << vect_[1] << " ";
  if (U > 2)
    std::cout << "Z: " << vect_[2] << std::endl;

  if (U > 3)
    {
      std::cout << "and: " << std::endl;
      for (unsigned int i = 3; i < U; ++i)
	std::cout << "Vector (" << i << "): " << vect_[i] << std::endl;
    }
}

template <unsigned int U, typename T>
std::string
Vector<U, T>::tostring (int size) const
{
  std::string res = "";

  T values[U];

  res += (vect_[0] / 256) + (vect_[1] / 256) * (size / 256);

  for (unsigned int i = 0; i < U; ++i)
    values[i] = (vect_[i] % 256);

  for (unsigned i = 0; i < U; ++i)
    res += (unsigned char) values[i];

  return res;
}

template <unsigned int U, typename T>
void
Vector<U, T>::fromstring (char* str, int size)
{
  int pos_x = ((unsigned char) str[0]) % (size / 256);
  int pos_y = ((unsigned char) str[0]) / (size / 256);

  for (unsigned i = 0; i < U; ++i)
    vect_[i] = ((unsigned char) str[i + 1]);

  vect_[0] += pos_x * 256;
  vect_[1] += pos_y * 256;
}

template <unsigned int U, typename T>
std::string
Vector<U, T>::tonet () const
{
  std::string res;

  for (unsigned i = 0; i < U; ++i)
  {
    char* c = (char*) &vect_[i];
    for (unsigned j = 0; j < sizeof (T); ++j)
      res += c[j];
  }

  return res;
}

template <unsigned int U, typename T>
void
Vector<U, T>::fromnet (const char* str, int)
{
  T f = 0;
  for (int i = 0; i < 3; ++i)
    {
      f = * (T*) str;
      vect_[i] = f;
      str += 4;
    }
}

template <unsigned int U, typename T>
std::ofstream&
operator<< (std::ostream& o, const Vector<U, T>& v)
{
  o << "[";
  for (unsigned int i = 0; i < U; ++i)
    o << v (i) << ", ";
  o << "]";
  return o;
}
